package org.liveboardgames.agricola.business;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.liveboardgames.agricola.access.IGameDao;
import org.liveboardgames.agricola.business.updater.GameUpdater;
import org.liveboardgames.agricola.domain.Change;
import org.liveboardgames.agricola.domain.Game;
import org.liveboardgames.agricola.domain.board.BoardTile;
import org.liveboardgames.agricola.domain.card.ActionCard;
import org.liveboardgames.agricola.domain.card.ImprovementCard;
import org.liveboardgames.agricola.domain.farm.Pasture;
import org.liveboardgames.agricola.domain.player.Player;
import org.liveboardgames.agricola.model.enums.FarmElementEnum;
import org.liveboardgames.agricola.model.enums.GameTypeEnum;
import org.liveboardgames.agricola.model.enums.ResourceTypeEnum;
import org.liveboardgames.agricola.model.structure.GameSendVisitor;
import org.liveboardgames.agricola.model.structure.Visitor;

public class CreateGameServiceImpl implements ICreateGameService {

  private IGameDao gameDao;

  private IPlayerService playerService;

  private IBoardTilesService boardTilesService;

  private IWaitingActionCardsService waitingActionCardService;

  private IMajorImprovementsService majorImprovementsService;

  private IRoundService roundService;

  public void setGameDao(IGameDao gameDao) {
    this.gameDao = gameDao;
  }

  public void setPlayerService(IPlayerService playerService) {
    this.playerService = playerService;
  }

  public void setBoardTilesService(IBoardTilesService boardTilesService) {
    this.boardTilesService = boardTilesService;
  }

  public void setWaitingActionCardService(IWaitingActionCardsService waitingActionCardService) {
    this.waitingActionCardService = waitingActionCardService;
  }

  public void setMajorImprovementsService(IMajorImprovementsService majorImprovementsService) {
    this.majorImprovementsService = majorImprovementsService;
  }

  public void setRoundService(IRoundService roundService) {
    this.roundService = roundService;
  }

  public Game createGame(List<Player> players, GameTypeEnum gameType) {

    // Check pre-conditions
    preProcessing(players, gameType);

    // Create a new empty game
    Game game = new Game();

    // Initialize the list of tiles, i.e. the board
    List<BoardTile> tiles = boardTilesService.createTiles(players.size(), gameType);
    game.setTiles(tiles);

    // Initialize the actions cards that will be turned face up at each
    // round
    List<ActionCard> waitingActionCards = waitingActionCardService.createWaitingActionCards();
    game.setWaitingActionCards(waitingActionCards);

    // Initialize the major improvements board
    Set<ImprovementCard> majorImprovements = majorImprovementsService.createMajorImprovements();
    game.setMajorImprovements(majorImprovements);

    // Basic player information (i.e. Name and Color, and later on probably
    // information like account or player ID) comes from the application
    // Need to add the rest though
    players = playerService.initializePlayers(players);
    game.setPlayers(players);
    game.setHasPlayerPlayedPeep(Boolean.FALSE);

    gamePostProcessing(game);

    gameDao.save(game);

    // Format the game to get rid of PersistentMaps
    Visitor visitor = new GameSendVisitor();
    game.acceptVisit(visitor);

    debug(game);

    // List<Change> changes = new ArrayList<Change>();
    // Change change = new Change(ChangesEnum.GAME, game);
    // changes.add(change);
    //
    // new AgricolaUpdateAdapter().publishGameUpdates(game.getId(), changes);

    return game;
  }

  private void gamePostProcessing(Game game) {
    // Randomize the list of players and defines the first player
    Collections.shuffle(game.getPlayers());
    game.setCurrentPlayer(game.getPlayers().get(0));

    // The first player has only two Food
    game.getPlayers().get(0).getFarm().getResources().put(ResourceTypeEnum.FOOD, 2);
  }

  private void debug(Game game) {
    for (Player player : game.getPlayers()) {
      player.getFarm().getResources().put(ResourceTypeEnum.REED, 3);
      player.getFarm().getResources().put(ResourceTypeEnum.WOOD, 10);
      player.getFarm().getResources().put(ResourceTypeEnum.STONE, 3);
      player.getFarm().getResources().put(ResourceTypeEnum.CLAY, 3);
      player.getFarm().getResources().put(ResourceTypeEnum.GRAIN, 3);
      player.getFarm().getTiles().get(1).setPeeps(null);
      player.getFarm().getTiles().get(2).setFarmElement(FarmElementEnum.WOODEN_ROOM);
      player.getFarm().getTiles().get(7).setFarmElement(FarmElementEnum.FIELD);
      player.getFarm().getTiles().get(7).addResource(ResourceTypeEnum.GRAIN, 3);
    }

    game.getPlayers().get(1).getFarm().getTiles().get(0).setPeeps(null);
    game.getPlayers().get(2).getFarm().getTiles().get(0).setPeeps(null);

    Pasture pasture = new Pasture();
    game.getPlayers().get(0).getFarm().getTiles().get(8).setPasture(pasture);
    game.getPlayers().get(0).getFarm().getTiles().get(11).setPasture(pasture);
    game.getPlayers().get(0).getFarm().getTiles().get(8).addResource(ResourceTypeEnum.SHEEP, 2);

    GameUpdater updater = new GameUpdater(game, new ArrayList<Change>());
    for (int i = 0; i < 13; i++) {
      updater.addNextActionCard();
    }

    gameDao.save(game);
  }

  private void preProcessing(List<Player> players, GameTypeEnum gameType) {
    if (players == null || players.size() == 0) {
      throw new IllegalArgumentException("The Set of players of a game should not be empty");
    }
    if (gameType == null) {
      throw new IllegalArgumentException("The game type of a game should not be null");
    }
  }

}
